﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using LastFmLib;
using LastFmLib.API20.Album;
using LastFmLib.API20.Artist;
using LastFmLib.API20.Auth;
using LastFmLib.API20.Tracks;
using LastFmLib.API20.Types;
using Shoozla.DataModel.Helper;


namespace Shoozla.DataModel
{
    public sealed class LASTFMService
    {
        private const String AppKey = "a0c4fb8c72433dad6651a47c956266a3";
        private const String Secret = "06c1629754f2401f1ac9604af35cdf4c";
        public AuthData Auth {private set; get;}
        private static volatile LASTFMService _instance;
        private static object _syncRoot = new Object();      

        public bool LastFMInitializated {
            get {
                lock (_syncRoot)
                {
                    if (Auth == null)
                        return false;
                    else
                    {
                        if (Auth.HasSession && Auth.HasToken && Auth.HasApiKey && Auth.HasSecret)
                            return true;
                        else
                            return false;
                    }
                }
            }
        }

        private LASTFMService() {
        }

        public static LASTFMService GetInstance() {
            if (_instance == null)
            {
                lock (_syncRoot)
                {
                    _instance = new LASTFMService();
                }
            }
            
            return _instance;
        }

        public void InitAuth()
        {
            lock (_syncRoot)
            {
                try
                {
                    MD5Hash key = new MD5Hash(AppKey, true);
                    MD5Hash secret = new MD5Hash(Secret, true);
                    Auth = new AuthData(key, secret, null);

                    AuthGetToken req = new AuthGetToken();
                    req.AuthData = Auth;
                    req.Start();
                    if (req.succeeded)
                    {
                        Auth.Token = req.Result;
                        Trace.WriteLine(String.Format(@"LASTFM: http://www.last.fm/api/auth/?api_key={0}&token={1}", AppKey, Auth.Token));
                        Auth.AskUserToGrantPermissions();
                    }
                    else
                    {
                        Trace.WriteLine("[ERROR] InitLastFM: AuthGetToken: " + req.errorMessage);
                        Auth = null;
                    }
                }
                catch (Exception e)
                {
                    Trace.WriteLine("[ERROR] InitLastFM: Exception: " + e.Message);
                    Auth = null;
                }
            }
        }

        public bool InitSession()
        {
            lock (_syncRoot)
            {
                if (Auth == null)
                    return false;

                AuthGetSession sk = new AuthGetSession(Auth.Token);
                sk.AuthData = Auth;
                sk.Start();
                if (sk.succeeded)
                {
                    Auth.Session = sk.Result;
                    return true;
                }
                else
                {
                    Trace.WriteLine("[ERROR] InitSession: AuthGetSession:" + sk.errorMessage);
                    Auth = null;
                    return false;
                }
            }
        }
    }

    public class LASTFMSearcher : CoverSearcher
    {
        public AuthData Auth;
        private LASTFMService _lastFMsrv;


        public LASTFMSearcher(ICoverStorage cache, CancellationTokenSource token, StatisticsLogger stats) : base(cache, token,stats) { }
        public LASTFMSearcher(AuthData auth) : base() { Auth = auth; }
        public LASTFMSearcher(AuthData auth, ICoverStorage cache, CancellationTokenSource token, StatisticsLogger stats) : this(cache,token,stats) { Auth = auth; }

        protected override void SetAddInInformation()
        {
            AddInName = "Last.FM";
            AddInDescription = "You need an account in www.lastfm.com";
        }

        public override Image GetIcon()
        {
            return Properties.Resources.logo;
        }

        public override bool Initialize() {
            _lastFMsrv = LASTFMService.GetInstance();
            if (!_lastFMsrv.LastFMInitializated)
            {
                _lastFMsrv.InitAuth();

                var res = AskToUser("You need to login to LASTFM website to proceed, click OK only after you logged on the website");
                if (!res)
                    return false;
                return _lastFMsrv.InitSession();
            }
            else 
                return true; 
        }

        public override Uri FindByAlbumNameInternal(String artist,String albumName)
        {
            if (String.IsNullOrEmpty(artist) || String.IsNullOrEmpty(albumName))
                return null;
            try
            {
                AlbumGetInfo albumInfo = new AlbumGetInfo(StringHelper.PrepareStringForWeb(artist), StringHelper.PrepareStringForWeb(albumName));

                albumInfo.AuthData = _lastFMsrv.Auth;                
                albumInfo.Start();
                if (albumInfo.succeeded && albumInfo.Result != null)
                {
                    Uri albumUri = null;
                    if (albumInfo.Result.ImageLarge != null)
                        albumUri = albumInfo.Result.ImageLarge;
                    else
                    {
                        if (albumInfo.Result.ImageMedium != null)
                            albumUri = albumInfo.Result.ImageMedium;
                        else
                            albumUri = albumInfo.Result.ImageSmall;
                    }
                    //Trace.WriteLine(String.Format("[INFO] LASTFMSearcher: FindByAlbumName: {0} = {1}", albumName, albumUri==null?"NULL":albumUri.ToString()));
                    return albumUri;
                }
                else
                    return null;
            }
            catch (Exception albumEx)
            {
                Trace.WriteLine(String.Format("[ERROR] LASTFMSearcher: FindByAlbumName: {0} - {1} ",albumName,albumEx.Message));
                return null;
            }
        }

        public override Uri FindBySongTitleInternal(String artist, String title)
        {
            try
            {
                TrackSearch track = new TrackSearch(StringHelper.PrepareStringForWeb(artist), StringHelper.PrepareStringForWeb(title), 20);
                track.AuthData = _lastFMsrv.Auth;
                track.Start();

                if (track.succeeded && track.Result != null)
                {
                    if (track.Result.Tracks.Count <= 0)
                    {
                       // Trace.WriteLine(String.Format("[INFO] LASTFMSearcher: FindBySongTitle: {0} - {1} = not found!", artist, title));
                        return null;
                    }

                    //Trace.WriteLine(String.Format("[INFO] LASTFMSearcher: FindBySongTitle: {0} - found {1} tracks", artist + " " + title, track.Result.Tracks.Count));                   
                    //save the only if it find a valid image
                    Uri trackUri = null;
                    foreach (Track t in track.Result.Tracks)
                    {
                        if (t.Title != null)
                        {
                         //   Trace.WriteLine(String.Format("[INFO] LASTFMSearcher: FindBySongTitle: {0} - cover={1}", song.Hash, t.ImageLarge));                            
                            if (t.Title.ToLowerInvariant().Contains(title))
                            {
                                if (t.ImageLarge != null)
                                {
                                    trackUri = t.ImageLarge;
                                    break;
                                }
                            }
                        }

                    }
                    return trackUri;
                }
                else
                {
                    throw new Exception("TrackSearch error");
                }
            }
            catch (Exception albumEx)
            {
                Trace.WriteLine(String.Format("[ERROR] LASTFMSearcher: FindBySongTitle: {0} - {1}",title,albumEx.Message));
                return null;
            }
        }

        public override Uri FindArtistInternal(String artist)
        {
            try
            {
                ArtistGetInfo artistInfo = new ArtistGetInfo(StringHelper.PrepareStringForWeb(artist));
                artistInfo.AuthData = _lastFMsrv.Auth;
                artistInfo.Start();
                if (artistInfo.succeeded && artistInfo.Result != null)
                {

                    Uri artistUri = null;
                    if (artistInfo.Result.ImageLarge != null)
                        artistUri = artistInfo.Result.ImageLarge;
                    else
                    {
                        if (artistInfo.Result.ImageMedium != null)
                            artistUri = artistInfo.Result.ImageMedium;
                        else
                            artistUri = artistInfo.Result.ImageSmall;
                    }

                    //Trace.WriteLine(String.Format("[INFO] LASTFMSearcher: FindArtist: {0} = {1}", artist, artistUri==null?"NULL":artistUri.ToString()));
                    return artistUri;
                }
                else
                {
                    Trace.WriteLine(String.Format("[INFO] FindArtist: {0} = not found!", artist));
                    return null;
                }
            }
            catch (Exception albumEx)
            {
                Trace.WriteLine(String.Format("[ERROR] LASTFMSearcher: FindArtist: {0} - {1}",artist,albumEx.Message));
                return null;
            }
        }
    }



}
